package org.yeasy.distinguish.util;


import cn.hutool.core.util.ObjectUtil;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;
import org.yeasy.common.util.CommonBeanUtil;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * 区分代理工具
 * The type Distinguish list proxy.
 *
 * @param <T> the type parameter
 */
public class DistinguishListProxy<T> {

    private final Class<T> type;

    @Accessors(chain = true)
    @Setter
    private Collection<T> oldTargets;

    @Accessors(chain = true)
    @Setter
    private Collection<T> newTargets;

    /**
     * Instantiates a new Distinguish list proxy.
     *
     * @param clazz the clazz
     */
    public DistinguishListProxy(Class<T> clazz) {
        this.type=clazz;
    }


    /**
     * Instantiates a new Distinguish list proxy.
     *
     * @param type       the type
     * @param oldTargets the old targets
     * @param newTargets the new targets
     */
    public DistinguishListProxy(Class<T> type, Collection<T> oldTargets, Collection<T> newTargets) {
        this.type = type;
        this.oldTargets = oldTargets;
        this.newTargets = newTargets;
    }

    @Getter
    private List<T> insertList;

    @Getter
    private List<T> updateList;

    @Getter
    private List<T> removeList;

    /**
     * Distinguish distinguish list proxy.
     *
     * @param field the field
     * @return the distinguish list proxy
     */
    public DistinguishListProxy<T> distinguish(String field){
        String getterName= CommonBeanUtil.calcGetterName(field);
        Method mMethod = null;
        try {
            mMethod = this.type.getDeclaredMethod(getterName);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        assert mMethod != null;

        this.insertList=new ArrayList<>();
        this.updateList=new ArrayList<>();
        this.removeList=new ArrayList<>();
        try {
            for (T mNew : this.newTargets) {
                boolean hasOld=false;
                for (T mOld : this.oldTargets) {
                    if (ObjectUtil.equal(mMethod.invoke(mNew),mMethod.invoke(mOld))) {
                        this.updateList.add(mNew);
                        hasOld=true;
                        break;
                    }
                }
                if(!hasOld){
                    this.insertList.add(mNew);
                }
            }
            for (T mOld : this.oldTargets) {
                boolean hasNew=false;
                for (T mNew : this.newTargets) {
                    if (ObjectUtil.equal(mMethod.invoke(mNew),mMethod.invoke(mOld))) {
                        hasNew=true;
                        break;
                    }
                }
                if(!hasNew){
                    this.removeList.add(mOld);
                }
            }
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }

        return this;
    }
}
